/*******************************************************************************
 * Copyright (c) 2010, 2015 git@git.oschina.net:kaiwill/springstage.git
 * <p/>
 * Licensed under the Apache License, Version 2.0 (the "License");
 *******************************************************************************/
package com.qinyeit.serviceapp.security.realm;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.qinyeit.serviceapp.entity.Employee;
import com.qinyeit.serviceapp.entity.system.ManagementAccount;
import com.qinyeit.serviceapp.entity.system.ManagementRole;
import com.qinyeit.serviceapp.security.token.RestaurantChainAuthenticationToken;
import com.qinyeit.serviceapp.service.organization.EmployeeService;
import com.qinyeit.serviceapp.service.system.ManagementAccountService;
import com.qinyeit.serviceapp.utils.SearchUtils;
import com.qinyetech.springstage.core.entity.search.Searchable;
import com.qinyetech.springstage.core.security.SimpleByteSource;
import com.qinyetech.springstage.core.security.StatelessSecurityToken;
import com.qinyetech.springstage.core.security.exception.BlankPasswordException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.map.HashedMap;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

import static com.qinyeit.serviceapp.security.PrincipalIdentifierKey.*;

/**
 * ClassName: ManagementAccountRealm <br/>
 * Function: 总后台安全认证 <br/>
 * date: 2017年10月20日 下午16:37:24 <br/>
 *
 * @author wuqing
 * @version
 * @since JDK 1.7
 */
@Slf4j
public class ManagementAccountRealm extends AccountRealm {
    @Autowired
    private ManagementAccountService systemAccountService;
    @Autowired
    private EmployeeService employeeService;
    public ManagementAccountRealm() {
        this.setAuthorizationCacheName("management:authorizationCache:");
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof StatelessSecurityToken;

    }
    /**
     * 登陆验证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    @SuppressWarnings("unchecked")
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        if(token instanceof RestaurantChainAuthenticationToken){
            RestaurantChainAuthenticationToken restaurantChainToken=(RestaurantChainAuthenticationToken)token;
            return doGetAuthenticationInfo(restaurantChainToken);

        }
        throw new AuthenticationException("token 不合法");
    }

    private AuthenticationInfo doGetAuthenticationInfo(RestaurantChainAuthenticationToken token) throws AuthenticationException{
//        StatelessSecurityToken statelessToken = (StatelessSecurityToken)token;
        log.info("--------------------访问 ： ");
        String accountName = (String) token.getPrincipal(); // 用戶名

//        log.info("statelessToken : {}",token);
//        log.info("json statelessToken : {}", JSON.toJSONString(accountName));

        if (token.getCredentials() == null) {
            throw new BlankPasswordException();
        }
        ManagementAccount account = null;
        //获取管理员账号 如果管理员账号为空 表示员工登录
        if (token.isAdmin()){
            account = systemAccountService.findByAdminAccount(accountName);
        }else {
            account=systemAccountService.findByAccountWithAdmin(accountName,token.getAdminAccount());
        }

        if (account == null) {
            throw new UnknownAccountException();// 没找到帐号
        }
        if (account.isLocked()) {
            throw new LockedAccountException(); // 帐号锁定
        }
        Date lastLoginDate = null;
        if (account.getLastLoginAt()!=null){
            lastLoginDate =new Date();
        }else {
            lastLoginDate=account.getLastLoginAt();
        }
        account.setLastLoginAt(new Date());//更新最后一次登录时间
        systemAccountService.update(account);

//        log.info("account: {}",JSON.toJSONString(account));

        //获取员工
        Searchable searchable = SearchUtils.newSearchableWithMerchantFilter(account.getMerchantGroupId());
        searchable.addSearchParam("account.id_eq",account.getId());
        Employee employee = employeeService.findOne(searchable);

//        log.info("emplpyee : {}",JSON.toJSONString(employee));

        Map principalMap=new HashedMap();
        principalMap.put(PRINCIPAL_ACCOUNT_NAME,accountName);//账号名称
        principalMap.put(PRINCIPAL_ACCOUNT_ID,account.getId()); //账号id
        principalMap.put(PRINCIPAL_IS_ADMIN,account.isAdmin());//是否是管理员
        principalMap.put(PRINCIPAL_TERMINAL_DEVICE,token.getTerminalDevice()); //平台类型，获取授权的时候使用
        principalMap.put(PRINCIPAL_LAST_LOGIN_AT,lastLoginDate);
        principalMap.put(PRINCIPAL_ACCOUNT_HEAD_URL,account.getHeadPic());
        principalMap.put(PRINCIPAL_ACCOUNT_REAL_NAME,account.getRealName());
        principalMap.put(PRINCIPAL_MERCHANT_GROUP_ID,account.getMerchantGroupId());
        principalMap.put(PRINCIPAL_EMPLOYEE_ID,employee.getId());
        principalMap.put(PRINCIPAL_EMPLOYEE_NAME,employee.getName());
        principalMap.put(PRINCIPAL_EMPLOYEE_MANAGE_BRANCH,employee.getAttachDataPermission());

        String uuid= UUID.randomUUID().toString();
        //产生密钥
        String securityKey=new Md5Hash(uuid,accountName).toString();
        principalMap.put(PRINCIPAL_SECURITY_KEY,securityKey);
        // 交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                principalMap , // 用户名
                account.getPasswordDigist(), // 密码
                new SimpleByteSource(account.getCredentialsSalt()),// salt=username+salt
                getName() // realm name
        );
        return authenticationInfo;
    }


    /**
     * 获取授权信息
     * @param principals
     * @return
     */
    @Override
    @SuppressWarnings("unchecked")
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        Map<String,Object> principalMap = ( Map<String,Object>) principals.getPrimaryPrincipal();
        String accountName=(String)principalMap.get(PRINCIPAL_ACCOUNT_NAME);
        boolean isAdmin = (boolean)principalMap.get(PRINCIPAL_IS_ADMIN);
        Long accountId = (Long)principalMap.get(PRINCIPAL_ACCOUNT_ID); //账号id
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

//        log.info("admin : {}",isAdmin);

        if(isAdmin){
            //超级管理员 所有权限
            authorizationInfo.setStringPermissions(Sets.newHashSet("*", "*:*", "*:*:*", "*:*:*:*"));  //超级管理员拥有所有权限
        }else {
            //指定权限字符串
            List<Map<String,Object>> mapList = systemAccountService.getPermissionCodeSet(accountId);
            Set<String> permissions = new HashSet<>();
            if(CollectionUtils.isNotEmpty(mapList)){
                for (Map<String, Object> map : mapList) {
                    permissions.add(map.get("code").toString());
                }
            }
//            log.info("-----permission :  : {}",permissions);
            authorizationInfo.setStringPermissions(permissions);
        }



//        Set<String> roleCodes= systemAccountService.findRoleCodeSet(accountName);
//        log.info("=============={}",Arrays.toString(roleCodes.toArray()));
        //指定角色字符串
//        authorizationInfo.setRoles(roleCodes);
//        if (roleCodes.contains(ManagementRole.ADMINISTRATOR_CODE)) { //如果是超级管理员
//            authorizationInfo.setStringPermissions(Sets.newHashSet("*", "*:*", "*:*:*", "*:*:*:*"));  //超级管理员拥有所有权限
//        } else {
//            //指定权限字符串
//            authorizationInfo.setStringPermissions(systemAccountService.findPermissionCodeSet(accountName));
//        }
        return authorizationInfo;
    }


    /**
     * 获取认证信息缓存的key
     * @param principals
     * @return
     */
    @SuppressWarnings("unchecked")
    @Override
    protected Object getAuthorizationCacheKey(PrincipalCollection principals) {
        Map<String,Object> principalMap= ( Map<String,Object>) principals.getPrimaryPrincipal();
        String id=principalMap.get(PRINCIPAL_ACCOUNT_ID).toString();
        return String.format("id:{%s}",id);
    }

    /**
     * 删除指定账户id的 认证缓存
     * @param accountId
     */
    @SuppressWarnings("unchecked")
    public void clearCachedAuthorizationInfo(String accountId) {
        Map<String,Object> map= Maps.newHashMap();
        map.put(PRINCIPAL_ACCOUNT_ID,accountId);
        PrincipalCollection principals= new SimplePrincipalCollection(map,getName());
        super.clearCachedAuthorizationInfo(principals);
    }

}
